﻿using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Model;

namespace ConAppCore.Test
{
    internal class TestSecurity
    {
        public static void Test()
        {
            //TestGetAlgorithmType();
            //TestComputeHash();
            //TestSymmetric();
            //TestSymmetric2();
            //TestSymmetricEncryptFile();
            //TestRSR();
            //TestRSRFile();
            //TestMoveBit();
            //TestZ();

            //TestZEncryptFolder();
            EncryptBMFolder();
        }

        private static void EncryptBMFolder()
        {
            long seed = 1750151598343L;
            byte[] key = SecurityEx.ZKey(seed, 128);
            string dstFilePath = @"D:\ddcc.data";
            SecurityEx.ZEncrypt(@"E:\xx", "*.*", SearchOption.AllDirectories, dstFilePath, key);
            SecurityEx.ZDecrypt(dstFilePath, @"D:\xx", key);
        }

        private static void TestZEncryptFolder()
        {
            long seed = 1750151598343L;
            byte[] key = SecurityEx.ZKey(seed, 128);
            string dstFilePath = @"E:\temp\ze.data";
            SecurityEx.ZEncrypt(@"E:\temp\ZK", "*.*", SearchOption.AllDirectories, dstFilePath, key);
            SecurityEx.ZDecrypt(dstFilePath, @"E:\temp\ZK2", key);
        }


        private static void TestZ()
        {
            string filePath = @"D:\Projects\DW\dic\E7";
            string text = File.ReadAllText(filePath);
            byte[] data = Encoding.UTF8.GetBytes(text);

            //byte[] key = new byte[] { 15, 26, 98, 45, 36, 89, 78, 96, 65 };
            //byte[] key = new byte[] { 15, 26 };
            //byte[] key = BitConverter.GetBytes(TimeEx.GetTimestamp());

            //long seed = TimeEx.GetTimestamp();
            long seed = 1750151598133L;
            byte[] key = SecurityEx.ZKey(seed, 128);

            byte[] encryptResult = SecurityEx.ZEncrypt(data, key);
            //byte[] encryptResult = File.ReadAllBytes(@"D:\Temp\E7.zz");
            //File.WriteAllBytes(@"D:\Temp\E7.zz", encryptResult);

            byte[] decryptResult = SecurityEx.ZDecrypt(encryptResult, key);

            string text2 = Encoding.UTF8.GetString(decryptResult);
            if (string.Equals(text, text2))
            {
                Console.WriteLine("TestZ ok.");
            }
            else
            {
                Console.WriteLine("TestZ fail.");
            }
        }

        private static void TestMoveBit()
        {
            string filePath = @"D:\Temp\Program.cs";
            string text = File.ReadAllText(filePath);
            byte[] data = Encoding.UTF8.GetBytes(text);
            byte[] encryptResult = CompressEx.CompressBytes(SecurityEx.MoveBitEncrypt(data));
            File.WriteAllBytes(@"D:\Temp\Program.dd", encryptResult);
            byte[] decryptResult = SecurityEx.MoveBitDecrypt(CompressEx.DecompressBytes(encryptResult));

            string text2 = Encoding.UTF8.GetString(decryptResult);
            if (string.Equals(text, text2))
            {
                Console.WriteLine("MoveBit ok.");
            }
            else
            {
                Console.WriteLine("MoveBit fail.");
            }
        }

        //[SupportedOSPlatform("windows")]
        private static void TestRSRFile()
        {
            string inputFilePath = @"D:\Temp\Program.cs";
            string outputFilePath = @"D:\Temp\Program.rsr";
            string filePath = @"D:\Temp\ProgramRSR.cs";
            FileEx.TryDeleFile(outputFilePath);
            FileEx.TryDeleFile(filePath);
            string text = File.ReadAllText(inputFilePath);
            RSAAlgorithmType algorithmType = RSAAlgorithmType.Default;
            RSAKeys key = SecurityEx.RSAKeys(2048);
            SecurityEx.RSAEncryptFile(inputFilePath, outputFilePath, key.PublicKey, algorithmType, RSAEncryptionPadding.OaepSHA1);
            SecurityEx.RSADecryptFile(outputFilePath, filePath, key.PrivateKey, algorithmType, RSAEncryptionPadding.OaepSHA1);

            string text3 = File.ReadAllText(filePath);
            if (string.Equals(text, text3))
            {
                Console.WriteLine("RSR FILE text ok.");
            }
            else
            {
                Console.WriteLine("RSR FILE text fail.");
            }
        }

        private static void TestRSR()
        {
            //数据长度与密钥长度关系,117-1024, 214-2048
            byte[] data = new byte[214];
            byte value = 0;
            for (int i = 0; i < data.Length; i++)
            {
                data[i] = value++;
            }
            RSAKeys key = SecurityEx.RSAKeys(2048);
            RSAAlgorithmType algorithmType = RSAAlgorithmType.Default;
            byte[] encryptResult = SecurityEx.RSAEncrypt(data, key.PublicKey, algorithmType, RSAEncryptionPadding.OaepSHA1);
            byte[] decryptResult = SecurityEx.RSADecrypt(encryptResult, key.PrivateKey, algorithmType, RSAEncryptionPadding.OaepSHA1);

            if (data.Length != decryptResult.Length)
            {
                Console.WriteLine("RSR data.Length != decryptResult.Length fail.");
                return;
            }

            for (int j = 0; j < data.Length; j++)
            {
                if (data[j] != decryptResult[j])
                {
                    Console.WriteLine("RSR data[j] != decryptResult[j] fail.");
                    return;
                }
            }

            Console.WriteLine($"RSR ok.");
        }

        private static void TestSymmetricEncryptFile()
        {
            Console.WriteLine("------------------------------");

            string inputFilePath = @"D:\Temp\Program.cs";
            string outputFilePath = @"D:\Temp\Program.en";
            string filePath = @"D:\Temp\Program2.cs";

            string text = File.ReadAllText(inputFilePath);

            byte[] key = null, iv = null;
            var arr = new SymmetricAlgorithmType[]
            {
                SymmetricAlgorithmType.Aes,
                SymmetricAlgorithmType.DES,
                SymmetricAlgorithmType.RC2,
                SymmetricAlgorithmType.TripleDES
            };


            foreach (var at in arr)
            {
                switch (at)
                {
                    case SymmetricAlgorithmType.Aes:
                        //key = Encoding.UTF8.GetBytes("qwertyuiasdfghjk");
                        //iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        key = new byte[16];
                        for (int i = 0; i < key.Length; i++)
                        {
                            key[i] = (byte)i;
                        }

                        iv = new byte[16];
                        for (int i = 0; i < iv.Length; i++)
                        {
                            iv[i] = (byte)i;
                        }
                        break;
                    case SymmetricAlgorithmType.DES:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.RC2:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.TripleDES:
                        key = Encoding.UTF8.GetBytes("ICryptoTransform");//至少16/24字节
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    default:
                        break;
                }


                SecurityEx.SymmetricEncryptFile(inputFilePath, outputFilePath, key, iv, at);
                SecurityEx.SymmetricDecryptFile(outputFilePath, filePath, key, iv, at);
                string text2 = File.ReadAllText(filePath);
                if (string.Equals(text, text2))
                {
                    Console.WriteLine($"{at.ToString()}  ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()}  fail.");
                }

                byte[] encryptResult2 = SecurityEx.SymmetricEncryptText(text, key, iv, at);
                string text3 = SecurityEx.SymmetricDecryptText(encryptResult2, key, iv, at);
                if (string.Equals(text, text3))
                {
                    Console.WriteLine($"{at.ToString()} text ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()} text fail.");
                }
            }

        }


        private static void TestSymmetric2()
        {
            Console.WriteLine("------------------------------");

            string filePath = @"D:\Temp\Program.cs";
            string text = File.ReadAllText(filePath);
            byte[] data = Encoding.UTF8.GetBytes(text);

            byte[] key = null, iv = null;

            var arr = new SymmetricAlgorithmType[]
            {
                SymmetricAlgorithmType.Aes,
                SymmetricAlgorithmType.DES,
                SymmetricAlgorithmType.RC2,
                SymmetricAlgorithmType.TripleDES
            };

            byte[] encryptResult = new byte[data.Length + 1000];
            int encryptResultLength, decryptResultLength;
            Span<byte> decryptResult = new Span<byte>(new byte[encryptResult.Length + 100]);

            foreach (var at in arr)
            {
                switch (at)
                {
                    case SymmetricAlgorithmType.Aes:
                        //key = Encoding.UTF8.GetBytes("qwertyuiasdfghjk");
                        //iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        key = new byte[16];
                        for (int i = 0; i < key.Length; i++)
                        {
                            key[i] = (byte)i;
                        }

                        iv = new byte[16];
                        for (int i = 0; i < iv.Length; i++)
                        {
                            iv[i] = (byte)i;
                        }
                        break;
                    case SymmetricAlgorithmType.DES:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.RC2:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.TripleDES:
                        key = Encoding.UTF8.GetBytes("ICryptoTransform");//至少16/24字节
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    default:
                        break;
                }


                encryptResultLength = SecurityEx.SymmetricEncrypt(data, encryptResult, 0, encryptResult.Length, key, iv, at);
                decryptResultLength = SecurityEx.SymmetricDecrypt(encryptResult, 0, encryptResultLength, decryptResult, key, iv, at);
                string text2 = Encoding.UTF8.GetString(decryptResult.Slice(0, decryptResultLength));
                if (string.Equals(text, text2))
                {
                    Console.WriteLine($"{at.ToString()}  ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()}  fail.");
                }

                byte[] encryptResult2 = SecurityEx.SymmetricEncryptText(text, key, iv, at);
                string text3 = SecurityEx.SymmetricDecryptText(encryptResult2, key, iv, at);
                if (string.Equals(text, text3))
                {
                    Console.WriteLine($"{at.ToString()} text ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()} text fail.");
                }
            }

        }

        private static void TestSymmetric()
        {
            string filePath = @"D:\Temp\Program.cs";
            string text = File.ReadAllText(filePath);
            byte[] data = Encoding.UTF8.GetBytes(text);

            byte[] key = null, iv = null;

            var arr = new SymmetricAlgorithmType[]
            {
                SymmetricAlgorithmType.Aes,
                SymmetricAlgorithmType.DES,
                SymmetricAlgorithmType.RC2,
                SymmetricAlgorithmType.TripleDES
            };


            foreach (var at in arr)
            {
                switch (at)
                {
                    case SymmetricAlgorithmType.Aes:
                        //key = Encoding.UTF8.GetBytes("qwertyuiasdfghjk");
                        //iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        key = new byte[16];
                        for (int i = 0; i < key.Length; i++)
                        {
                            key[i] = (byte)i;
                        }

                        iv = new byte[16];
                        for (int i = 0; i < iv.Length; i++)
                        {
                            iv[i] = (byte)i;
                        }
                        break;
                    case SymmetricAlgorithmType.DES:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.RC2:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.TripleDES:
                        key = Encoding.UTF8.GetBytes("ICryptoTransform");//至少16/24字节
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    default:
                        break;
                }


                byte[] encryptResult = SecurityEx.SymmetricEncrypt(data, key, iv, at);
                byte[] decryptResult = SecurityEx.SymmetricDecrypt(encryptResult, key, iv, at);
                string text2 = Encoding.UTF8.GetString(decryptResult);
                if (string.Equals(text, text2))
                {
                    Console.WriteLine($"{at.ToString()}  ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()}  fail.");
                }

                byte[] encryptResult2 = SecurityEx.SymmetricEncryptText(text, key, iv, at);
                string text3 = SecurityEx.SymmetricDecryptText(encryptResult2, key, iv, at);
                if (string.Equals(text, text3))
                {
                    Console.WriteLine($"{at.ToString()} text ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()} text fail.");
                }
            }

        }

        private static void TestComputeHash()
        {
            string text = @"D:\Temp\Program.cs";
            byte[] data = File.ReadAllBytes(text);
            byte[] hash1 = SecurityEx.ComputeHash(data, HashAlgorithmType.SHA512);
            Console.WriteLine($"hash1:{ConvertEx.BytesToHexadecimaString(hash1, false, null)}");
        }

        private static void TestGetAlgorithmType()
        {
            Type targetType = typeof(RSA);
            Type[] types = targetType.Assembly.GetTypes();
            var hashClass = types.Where(t => { return !t.IsAbstract && t.IsSubclassOf(targetType); }).ToArray();
            StringBuilder sb = new StringBuilder();
            foreach (var type in hashClass)
            {
                sb.AppendLine(type.Name);
            }
            string str = sb.ToString();

            /*
             * HashAlgorithm子类
             * HMACMD5
             * HMACSHA1
             * HMACSHA256
             * HMACSHA384
             * HMACSHA512
             * HMACSHA3_256
             * HMACSHA3_384
             * HMACSHA3_512
             * MD5CryptoServiceProvider
             * SHA1CryptoServiceProvider
             * SHA1Managed
             * SHA256CryptoServiceProvider
             * SHA256Managed
             * SHA384CryptoServiceProvider
             * SHA384Managed
             * SHA512CryptoServiceProvider
             * SHA512Managed



             * 对称加密SymmetricAlgorithm子类
             * AesCryptoServiceProvider
             * AesManaged
             * RijndaelManaged
             * AesCng
             * DESCryptoServiceProvider
             * RC2CryptoServiceProvider
             * TripleDESCng
             * TripleDESCryptoServiceProvider
             * 
             * 非对称加密RSA子类
             * RSACng
             * RSAOpenSsl
             * RSACryptoServiceProvider
             * 
             * 
             * RSACng
             * RSAOpenSsl
             * RSABCrypt                默认RSA.Create()
             * RSACryptoServiceProvider
             * */
        }

    }
}
